#ifndef PIDDEVICE_H
#define PIDDEVICE_H

#include "stdint.h"

#ifdef __cplusplus
extern "C"
{
#endif

#ifdef _PID_MODULE_
#define PID_EXT
#else
#define PID_EXT extern
#endif

#define Q_VAL_1_0F (0x8000L)	  
#define Q_VAL_0_5F (0x4000L)	  
#define Q_VAL_0_25F (0x2000L)	  
#define Q_VAL_0_125F (0x1000L)	  
#define Q_VAL_NV1_0F (-0x8000L)	  
#define Q_VAL_NV0_5F (-0x4000L)	  
#define Q_VAL_NV0_25F (-0x2000L)  
#define Q_VAL_NV0_125F (-0x1000L) 

#define _PID_P_POS 0
#define _PID_I_POS 1
#define _PID_D_POS 2
#define _PID_AR_POS 3
#define _PID_T_POS 4

#define PID_DMOD_PV_COM 0
#define PID_DMOD_PV_SEM 1
#define PID_DMOD_PO_SEM 2

	typedef enum
	{
		PID_DWK_NONE = 0,
		PID_DWK_LIN_UP,	   
		PID_DWK_LIN_DN,	   
		PID_DWK_LIN_UP_DN, 
		PID_DWK_LAD_UP,	   
		PID_DWK_LAD_DN,	   
		PID_DWK_LAD_UP_DN, 
	} PID_DWK_TYPE;

	typedef enum
	{
		PID_DZ_MD_NOR = 0, 
		PID_DZ_MD_NEV = 1, 
		PID_DZ_MD_PST = 2, 
	} PID_DZM_TYPE;

	typedef struct
	{
		struct
		{
			PID_DWK_TYPE dv_weak_type;	 
			PID_DZM_TYPE dead_zone_mode; 
			uint8_t i_slope_mode;		 
			uint8_t i_ladder_en;		 
			uint8_t d_limit_en;			 
			uint8_t ctrz_en;			 
			uint8_t d_mode;				 
		} func;							 
		struct							 
		{								 
			uint16_t kt_sv;				 
			uint16_t kt_cycle;			 
			uint16_t P, I, D;			 
			uint16_t kt_cnt;			 
		} cfg;							 
		int16_t iout_min;				 
		int16_t iout_max;				 
		float dead_zone;				 
		struct							 
		{								 
			float sp_pfac;				 
			float slope_coef;			 
			float slope_zone;			 
			float slope_min;			 
			float slope_max;			 
			float ladder_site;			 
			float ladder_zone;			 
			float ladder_base;			 
		} icfg;							 
		float d_limit;					 
		float ctr_zone;					 
		float out_min;					 
		float out_max;					 
		float sv;						 
		float pv;						 
		struct							 
		{								 
			float fac;					 
			float offset;				 
			float flt;					 
			int32_t inc_max;			 
		} out_cfg;						 
		struct							 
		{								 
			float up_y0;				 
			float up_y1;				 
			float dn_y0;				 
			float dn_y1;				 
			float site;					 
			float max;					 
			float min;					 
		} dv_weak;

		struct
		{
			uint8_t ctrz;
			uint8_t d_mode;
		} st;
		int32_t out;   
		float out_adj; 
		struct
		{
			float out_coef;			 
			float out_coef_flt;		 
			float kp, ki, kd, dft;	 
			uint16_t Po, Io, Do, To; 
			float pv_old;
			float sv_old;
			float uk_pre;
		} aux;
		float pvd;
		float uk;
		float ik, dk;
		uint32_t check_err_cnt; 
		struct
		{
			float lmn;
			float lmn_old;
			float rueck, rest_diff;
		} ddd;
		uint8_t dv_clr_req;
	} pid_type;

	typedef struct
	{
		uint32_t auto_set_time;
		uint8_t ctr_dir; 
		uint8_t state;	 
		uint16_t rise_time;
		uint16_t fall_time;
		uint16_t P;
		uint16_t I;
		uint16_t D;
		float pv; 
		float sv; 
		float min;
		float max;
		float ctr_zone;			
		float id_coef;			
		pid_type *pid;			
		void (*par_save)(void); 
	} pid_tune_type;

	typedef struct
	{
		uint32_t check_err_cnt;
		
		uint8_t p_dis;		 
		uint8_t d_limit_p;	 
		uint8_t i_coef_en;	 
							 
		uint16_t kt;		 
		uint16_t kt_cnt;	 
							 
		int32_t q_sv;		 
		int32_t q_pv;		 
		int32_t q_dead_zone; 
		int32_t q_ki_coef;	 
							 
		int32_t q_p;		 
		int16_t i;			 
		int16_t d;			 
		int32_t p_old;		 
		int16_t i_old;
		int16_t d_old;
		uint16_t t_old;
		
		int32_t q_kp;	   
		int32_t q_ki;	   
		int32_t q_kd;	   
		int32_t q_dft;	   
		int32_t q_dv;	   
						   
		int32_t q_ival;	   
		int32_t q_pv_old;  
		int32_t q_err_old; 
						   
		int32_t q_imax;	   
		int32_t q_max;	   
		int32_t q_min;	   
						   
		int32_t q_out_flt; 
		int32_t q_out_fac; 
		int32_t q_out;	   
		int16_t out;	   
	} q_pid_type;

	void PidClr(pid_type *pid);				
	void PidDvClr(pid_type *pid);			
	void PidPvSet(pid_type *pid, float pv); 
	void PidSvSet(pid_type *pid, float sv); 

	void IndPid(pid_type *pid);

	void PidOutWeaken(pid_type *pid, float Coef);
	void PidUpdate(pid_type *pid, uint16_t *ParTab, float DutyMin, float DutyMax);

	uint8_t PidAutoSet(pid_tune_type *tune_obj);
	void PidAutoSetStart(pid_type *pid, pid_tune_type *tune_obj);
	void PidAutoSetExit(pid_tune_type *tune_obj);
	void PidAutoSetCal(pid_tune_type *tune_obj);

	int32_t q_pid_update(q_pid_type *pid);
	int32_t q_pid_cal(q_pid_type *pid);
	void q_pid_clr(q_pid_type *pid);
	void q_pid_dv_clr(q_pid_type *pid);

#undef PID_EXT

#ifdef __cplusplus
}
#endif

#endif 
